import { IProxy } from '@/common/types'
import Browser from 'webextension-polyfill'
import { InvokeResponse } from '@/common/invoke-response'
import { InvokeResponseCode } from '@/common/constant'

class Proxy implements IProxy {
  eventHandlers = {}

  // eslint-disable-next-line @typescript-eslint/ban-types
  on(command: string, handler: Function) {
    if (typeof handler !== 'function') {
      throw new Error('callback should be function')
    }
    this.eventHandlers[command] = handler
  }

  runtimeInvoke(command: string, params: unknown) {
    console.log('runtimeInvoke command:' + command, 'params:', params)
    return new Promise((resolve, reject) => {
      Browser.runtime
        .sendMessage({
          command: [command],
          params: params,
        })
        .then((invokeResult) => {
          console.log('runtimeInvoke command:' + command, 'result:', invokeResult)
          if (invokeResult.code === InvokeResponseCode.Fail) {
            reject(invokeResult)
            return
          }
          resolve(invokeResult)
        })
    })
  }

  tabInvoke(tabId: number, command: string, params: unknown) {
    console.log('tabInvoke command:', command, 'params:', params)
    return new Promise((resolve, reject) => {
      Browser.tabs
        .sendMessage(tabId, {
          command: [command],
          params: params,
        })
        .then((invokeResult) => {
          console.log('tabInvoke command:' + command, 'result:', invokeResult)
          if (invokeResult.code === InvokeResponseCode.Fail) {
            reject(invokeResult)
            return
          }
          resolve(invokeResult)
        })
    })
  }

  private static log(message, result?) {
    const { command, params } = message
    if (result) {
      console.log('receive command:' + command, 'receive params', params, `----->result`, result)
      return
    }
    console.log('receive command', command, 'receive params', params)
  }

  listen() {
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    Browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
      Promise.resolve()
        .then(() => {
          const { command, params } = message
          const handler = this.eventHandlers[command]
          if (typeof handler !== 'function') {
            throw new Error('handler not found for command: ' + command)
          } else {
            try {
              return handler(params)
            } catch (e) {
              return Promise.reject(e)
            }
          }
        })
        .then((result) => {
          Proxy.log(message, result)
          const returnMessage = result && result.message ? result.message : '成功'
          const data = result && result.data ? result.data : undefined
          sendResponse(InvokeResponse.success(returnMessage, data))
        })
        .catch((error) => {
          Proxy.log(message, error)
          sendResponse(InvokeResponse.fail(error))
        })
      return true
    })
  }
}

const proxy = new Proxy()

export default proxy
